Spring Boot AOP系列之AOP原理介绍
序言:在本文中,jdk动态代理和cglib代理的核心原理,我都会一一讲到,看本文的时候可以结合着上文看,了解创建的过程,创建的生命周期,才能知晓原理
一、JDK动态代理原理
1、前言
  其实大家看了上文的demo肯定会有所疑惑,为什么实现了一个InvocationHandler接口就可以实现切面的植入了,就可以在写好的函数方法上面,植入我们的代码呢?是不是很神奇,惊不惊喜,意不意外。OK,废话不多说,下面跟着我的思路,走一遍源代码。
2、介绍
上文中提到了,Spring jdk动态代理最核心的一句话莫过于下面这句话
| 
 | 
 | 
走进newProxyInstance这个方法
| 
 | 
 | 
getProxyClass0核心方法片段如下:
| 
 | 
 | 
proxyClassCache是这样的
| 
 | 
 | 
ProxyClassFactory是Proxy的一个静态内部类,实现了WeakCache的内部接口BiFunction的apply方法,代码如下:
| 
 | 
 | 
我们注意一下这行代码:
| 
 | 
 | 
进去:
| 
 | 
 | 
| 
 | 
 | 
在启动项目的时候,虚拟机设置一下这个参数sun.misc.ProxyGenerator.saveGeneratedFiles为true,就可以打印出代理对象的字节码文件。
PS:其实我们还有很多方法获取字节码文件,后文中介绍
OK,我们看下我们生成的字节码文件长什么样子:

我们可以清楚的看到生成的代理文件,实现了我们的自己需要的代理的接口QueryUserInfoBiz ,实现了SpringProxy接口 ,继承了Proxy类等。再来看看我们普通的一个方法,是如何被代理的。
insertUserInfoV5这个方法被代理之后,被植入了一段代码,super.h.invoke方法 , super表示Proxy这个夫类,h表示Proxy里面的一个属性,是InvocationHandler类型的,回忆一下,我们在手动创建jdk动态代理的时候,是不是需要指定一个InvocationHandler,这里就是起这个作用的,比如说在上个例子中,是我们自己写的MyInvocationHandler类,但是在Spring中,我们没有指定这个handler,那到底调用的是谁呢?
接上回:
在我们最开始用缓存创建那一段的时候,后面还有这样一段代码。这段代码的作用是让handler作为参数调用构造方法来获得代理类的实例
| 
 | 
 | 
实际上,调用者是,一般而言,谁去准备创建proxy,谁一般就是这个handler,比如我们这里讲的aop里面,创建者就是JdkDynamicAopProxy这个类,这个类他实现了InvocationHandler接口,所以他被作为参数传进去了,自然而言,当代理类里面的方法被调用的时候,他的invoke方法就会被唤醒。
二、CGLib原理介绍
我们再来看看Cglib代理
先来看看Cglib手动创建的一个简单代码:
| 
 | 
 | 
核心方法自然是create方法,走进去看一下
| 
 | 
 | 
createHelper方法
| 
 | 
 | 
调用了super.create方法,核心代码如下:
| 
 | 
 | 
然后看generate方法
| 
 | 
 | 
再看generateClass方法,这个就是生成代理文件的最核心逻辑了,先看Enhancer里面的generateClass 方法,
| 
 | 
 | 
这段就是生成字节码的核心逻辑,这段里面有很复杂的调用逻辑,我们这里不作详细介绍。
我们也有办法拿到CGLIB生成的代理文件,我这里不赘述,后面开一篇博客讲,这里面也挺麻烦的,当初我也找了很久。
OK,我们来看一下某一份生成好的代理字节码文件

这个代理类继承了我们被代理的类或者接口,然后实现了SpringProxy、Advised接口等, 首先当我们调用addOneCityV8方法的时候,代理类会先去看CGLIB$CALLBACK_0 这个属性为不为空,这个是一个MethodIntercepter类型的 ,如果为空就调用一个绑定方法,CGLIB$BIND_CALLBACKS ,它负责从一个叫做CGLIB$THREAD_CALLBACKS 的ThreadLocal对象中拿或者叫做CGLIB$STATIC_CALLBACKS的Callback数组中拿。拿到了之后就执行intercept方法。
那么这里有个问题,回调类到底是如何选择的呢?
这里的处理逻辑和JDK动态代理类似,回调类基于一种,谁创建,谁负责的逻辑,已AOP创建动态代理为例,CglibAopProxy这个类在创建代理的时候,会调用一个 getCallbacks方法,在CglibAopProxy 中可以搜索到,代码如下:
| 
 | 
 | 
根据摘取的部分片段可以得知,他是跟配置相关的,如果你没有作任何配置,那么系统一般首选DynamicAdvisedInterceptor 这个拦截器。也就是回调类就是DynamicAdvisedInterceptor ,会调用他里面的intercept方法。
完毕。
 
		